package com.whfc.iot.mach.context;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.whfc.common.spring.AppContextUtil;
import com.whfc.hdc.dto.AppDeviceParamDTO;
import com.whfc.hdc.dto.DeviceUpgradeDTO;
import com.whfc.hdc.service.AppDeviceOtaService;
import com.whfc.hdc.service.AppDeviceService;
import com.whfc.iot.autoconfigure.BrokerProperties;
import com.whfc.iot.mach.entity.UpgradeCacheKey;
import com.whfc.iot.session.Session;
import com.whfc.iot.session.SessionManager;
import com.whfc.iot.session.SessionSynchronizer;
import com.whfc.iot.session.impl.SessionManagerImpl;
import com.whfc.iot.session.impl.SessionSynchronizerImpl;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

/**
 * @Description: MACH全局配置
 * @author: xugcheng
 * @version: 1.0
 * @date: 2020-12-03 14:29
 */
@Configuration
public class MachContext {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 初始session保存数量
     */
    public static final int ONLINE_SESSIONS = 1024;

    @Autowired
    private BrokerProperties brokerProperties;

    @DubboReference(interfaceClass = AppDeviceOtaService.class, version = "1.0.0")
    private AppDeviceOtaService upgradeService;

    @DubboReference(interfaceClass = AppDeviceService.class, version = "1.0.0")
    private AppDeviceService deviceService;

    @Bean
    public SessionManager sessionManager() {
        ConcurrentMap<String, Session> channelId2sessionMap = new ConcurrentHashMap<>(ONLINE_SESSIONS);
        ConcurrentMap<String, String> deviceId2channelIdMap = new ConcurrentHashMap<>(ONLINE_SESSIONS);
        SessionManager sessionManager = new SessionManagerImpl(channelId2sessionMap, deviceId2channelIdMap);
        return sessionManager;
    }

    @Bean
    public SessionSynchronizer sessionSynchronizer() {
        SessionSynchronizer synchronizer = new SessionSynchronizerImpl(brokerProperties.getName(), sessionManager());
        synchronizer.run();
        return synchronizer;
    }

    @Bean
    @ConditionalOnMissingBean
    public AppContextUtil appContextUtil() {
        return new AppContextUtil();
    }

    /**
     * 硬件参数设置本地缓存
     *
     * @return
     */
    @Bean(name = "deviceParamCache")
    public LoadingCache<Integer, List<AppDeviceParamDTO>> deviceParamCache() {
        LoadingCache<Integer, List<AppDeviceParamDTO>> loadingCache = CacheBuilder.newBuilder().initialCapacity(512).maximumSize(10240).expireAfterWrite(1, TimeUnit.MINUTES).build(new CacheLoader<Integer, List<AppDeviceParamDTO>>() {
            @Override
            public List<AppDeviceParamDTO> load(Integer key) throws Exception {
                logger.info("加载硬件参数设置缓存,key:{}", key);
                return deviceService.getDeviceParam(key);
            }
        });

        return loadingCache;
    }

    /**
     * 硬件升级配置本地缓存
     *
     * @return
     */
    @Bean(name = "deviceUpgradeCache")
    public LoadingCache<UpgradeCacheKey, DeviceUpgradeDTO> deviceUpgradeCache() {
        LoadingCache<UpgradeCacheKey, DeviceUpgradeDTO> loadingCache = CacheBuilder.newBuilder().initialCapacity(512).maximumSize(10240).expireAfterWrite(5, TimeUnit.MINUTES).build(new CacheLoader<UpgradeCacheKey, DeviceUpgradeDTO>() {
            @Override
            public DeviceUpgradeDTO load(UpgradeCacheKey key) throws Exception {
                logger.info("加载硬件升级配置缓存,key:{}|{}|{}|{}", key.getDeviceId(), key.getDeviceType(), key.getMasterVer(), key.getSlaveVer());
                return upgradeService.getDeviceUpgrade(key.getDeviceType(), key.getDeviceId(), key.getMasterVer(), key.getSlaveVer());
            }
        });

        return loadingCache;
    }
}
